home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / WASTE Object Handlers 1.2.6.sit / WASTE Object Handlers 1.2.6 / Handler Source / WE_snd_Handler.c < prev   
Text File  |  1997-07-21  |  10KB  |  411 lines

  1. // Sound Object Handler for the WASTE Text Engine
  2. // by Michael F. Kamprath, kamprath@kagi.com
  3. // maintenance by John C. Daub, hsoi@eden.com
  4. //
  5. // v1.0, 16 March 1995
  6. // v1.0.1, 13 May 1995, changed the sound playing code a little.  Also added gestalt
  7. //                        check for sound recording device when CreateNewSoundObject()
  8. //                        is called.
  9. // v1.1, 5 June 95, Made some changes recomended by Chris Thomas, <THUNDERONE@delphi.com>:
  10. //            -    Playing an object's sound is done by ultilizing the object's data
  11. //                directly rather than making a copy.  Using PlaySoundHandle() for
  12. //                your sounds still makes a copy.
  13. //            -    Added the public routines StopCurrentSound() and IsSoundPlaying().
  14. //            -    Option to have the sound sound created at the handler's initilization.
  15. //            -    Added InstallSoundObject() to install sound object handler only.
  16. //
  17. // v1.2, 28 March 1996.  Bug fixes by John C. Daub <mailto:hsoi@eden.com>
  18. //            -    Removed a not operator from SoundIsPlaying() so the function works correctly
  19. //            -    Adjusted CheckSoundStatus() to work with the fixed SoundIsPlaying()
  20. //            -    Minor updates: more precompiler directives, WASTE 1.2a5 compatability
  21. //
  22. // v1.2.2, 16 July 1996. Added compatability with WASTE 1.2 and CW9
  23. //                         Restructured installation routines
  24. //
  25. // v1.2.4, 16 January 1997.  Removed the declaration of CreateNewSoundChannel()
  26. //                from WE_snd_Handler.h.  If this file was compiled with "Activate
  27. //                C++ Compiler" turned on (then compiling this C file as C++), there
  28. //                would be an error of inconsistent linkage because an 'extern'
  29. //                object was then getting redeclared as 'static'.  Hopefully this won't
  30. //                cause any problems for people.
  31. //
  32. // v1.2.5, 25 April 1997.  Added a gCurrentSound != nil check in CheckSoundStatus() just to be safe
  33. //
  34.  
  35. #ifndef _WASTE_
  36. #include "WASTE.h"
  37. #endif
  38.  
  39. #ifndef __GESTALT__
  40. #include <Gestalt.h>
  41. #endif
  42.  
  43. #include "WE_snd_Handler.h"
  44. #ifndef _WASTEOBJECTS_
  45. #include "WASTE_Objects.h"
  46. #endif
  47.  
  48. #ifndef true
  49. #define true 1
  50. #endif
  51.  
  52. #ifndef false
  53. #define false 0
  54. #endif
  55.  
  56. //
  57. // Local only routines
  58. //
  59.  
  60. static    OSErr    PlayCurrentGlobalSound( void );
  61. static    SndChannelPtr    CreateNewSoundChannel( void );
  62.  
  63. //
  64. // Sound Channel and current playing sound pointers
  65. //
  66. static SndChannelPtr    gSoundChannel = nil;
  67. static SndListHandle    gCurrentSound = nil;
  68. static short            gCurSoundHandleStatus = 0;
  69.  
  70. #define        kIsWASTESound        0x0100
  71.  
  72.  
  73.  
  74. void    InitSoundObjectHandler( void )
  75. {
  76. #if CREATE_CHANNEL_AT_INIT
  77.     gSoundChannel = CreateNewSoundChannel();
  78. #endif
  79. }
  80.  
  81.  
  82. OSErr    InstallSoundObject( WEReference theWE )
  83. {
  84. OSErr    iErr;
  85.  
  86. #ifdef __cplusplus
  87.     static WENewObjectUPP           newSndUPP = NewWENewObjectProc(HandleNewSound);
  88.     static WEDisposeObjectUPP       disposeSndUPP = NewWEDisposeObjectProc(HandleDisposeSound);
  89.     static WEDrawObjectUPP          drawSndUPP = NewWEDrawObjectProc(HandleDrawSound);
  90.     static WEClickObjectUPP         clickSndUPP = NewWEClickObjectProc(HandleClickSound);
  91. #else
  92.     static WENewObjectUPP           newSndUPP = NULL;
  93.     static WEDisposeObjectUPP       disposeSndUPP = NULL;
  94.     static WEDrawObjectUPP          drawSndUPP = NULL;
  95.     static WEClickObjectUPP         clickSndUPP = NULL;
  96.  
  97.     if ( newSndUPP == NULL )
  98.         newSndUPP = NewWENewObjectProc(HandleNewSound);
  99.     if ( disposeSndUPP == NULL )
  100.         disposeSndUPP = NewWEDisposeObjectProc(HandleDisposeSound);
  101.     if ( drawSndUPP == NULL )
  102.         drawSndUPP = NewWEDrawObjectProc(HandleDrawSound);
  103.     if ( clickSndUPP == NULL )
  104.         clickSndUPP = NewWEClickObjectProc(HandleClickSound);
  105. #endif
  106.  
  107.     if ( newSndUPP != NULL )
  108.         iErr = WEInstallObjectHandler(kTypeSound, weNewHandler, (UniversalProcPtr)newSndUPP, theWE);
  109.     else
  110.         iErr = weUnknownObjectTypeErr;
  111.     if (iErr) return(iErr);
  112.     
  113.     if ( disposeSndUPP != NULL )
  114.         iErr = WEInstallObjectHandler(kTypeSound, weDisposeHandler, (UniversalProcPtr)disposeSndUPP, theWE);
  115.     else
  116.         iErr = weUnknownObjectTypeErr;
  117.     if (iErr) return(iErr);
  118.     
  119.     if ( drawSndUPP != NULL )
  120.         iErr = WEInstallObjectHandler(kTypeSound, weDrawHandler, (UniversalProcPtr)drawSndUPP, theWE);
  121.     else
  122.         iErr = weUnknownObjectTypeErr;
  123.     if (iErr) return(iErr);
  124.     
  125.     if ( clickSndUPP != NULL )
  126.         iErr = WEInstallObjectHandler(kTypeSound, weClickHandler, (UniversalProcPtr)clickSndUPP, theWE);
  127.     else
  128.         iErr = weUnknownObjectTypeErr;
  129.     if (iErr) return(iErr);
  130.     
  131.     return(noErr);
  132. }
  133.  
  134. //
  135. // New Object Handler for sounds
  136. //
  137. pascal OSErr    HandleNewSound(Point *defaultObjectSize,WEObjectReference objectRef)
  138. {
  139. #pragma unused (objectRef)
  140.  
  141.     (*defaultObjectSize).h = 32;
  142.     (*defaultObjectSize).v = 32;
  143.  
  144.     return(noErr);
  145. }
  146. //
  147. // Dispose Object handler for sounds
  148. //
  149.  
  150. pascal OSErr    HandleDisposeSound(WEObjectReference objectRef )
  151. {
  152. SndListHandle    theSound;
  153.  
  154.     theSound = (SndListHandle)WEGetObjectDataHandle(objectRef);
  155.  
  156.     if (theSound == gCurrentSound)
  157.         StopCurrentSound();
  158.         
  159.     DisposeHandle((Handle)theSound);
  160.  
  161.     return(MemError());
  162. }
  163. //
  164. // Draw Object handler for sounds
  165. //
  166. pascal OSErr    HandleDrawSound(Rect *destRect, WEObjectReference objectRef )
  167. {
  168. #pragma unused (objectRef)
  169.  
  170. OSErr    iErr;
  171.     
  172.     iErr = PlotIconID(destRect,atNone,ttNone,kSoundIconID);
  173.     
  174.     return( iErr );
  175. }
  176. //
  177. // Click Object Handler for sounds
  178. //
  179.  
  180. pascal Boolean    HandleClickSound(    Point hitPt, 
  181.                             short modifiers, 
  182.                             long clickTime, 
  183.                             WEObjectReference objectRef)
  184. {
  185. #pragma unused ( hitPt, clickTime)
  186.  
  187. OSErr            iErr;
  188.  
  189.     if (modifiers & 0x0001)         // look for double-clicks
  190.     {
  191.         iErr = StopCurrentSound();
  192.         
  193.         gCurrentSound = (SndListHandle)WEGetObjectDataHandle( objectRef );
  194.         iErr = PlayCurrentGlobalSound();
  195.         gCurSoundHandleStatus += kIsWASTESound;
  196.         
  197.         if (!iErr)
  198.             return(true);
  199.         else
  200.         {
  201.             StopCurrentSound();
  202.             return(false);
  203.         }
  204.     }
  205.     else
  206.         return(false);
  207.  
  208. }
  209.  
  210. //
  211. // PlaySelectedSound()
  212. //        If a sound object, and only a sound object, is selected,
  213. //        PlaySelectedSound() will play it.
  214. //
  215. OSErr    PlaySelectedSound( WEReference theWE )
  216. {
  217. WEObjectReference    objectRef;
  218. SndListHandle        theSound;
  219. OSErr                iErr = noErr;
  220.  
  221.     iErr = WEGetSelectedObject( &objectRef, theWE );
  222.     if (!iErr)
  223.     {
  224.         theSound = (SndListHandle)WEGetObjectDataHandle( objectRef );
  225.         iErr = PlaySoundHandle( theSound );
  226.     }
  227.         
  228.     return( iErr );
  229. }
  230. //
  231. // CreateNewSoundObject()
  232. //        Uses built in sound recording to create a new sound object.
  233. //
  234. OSErr    CreateNewSoundObject( WEReference theWE )
  235. {
  236. OSErr            iErr;
  237. SndListHandle    sndHandle = nil;
  238. long            gestaltResponse;
  239. Point            corner = {32,32};
  240.  
  241.     iErr = Gestalt(gestaltSoundAttr, &gestaltResponse);
  242.     if ( (iErr == noErr)&&(gestaltResponse&gestaltHasSoundInputDevice))
  243.     {
  244.         iErr = SndRecord(nil,corner,siGoodQuality,&sndHandle);
  245.     
  246.         if (iErr == noErr)
  247.         {
  248.             corner.h = 32;
  249.             corner.v = 32;
  250.             WEInsertObject( kTypeSound, (Handle)sndHandle, corner, theWE );
  251.         }
  252.     }
  253.     return( iErr );
  254. }
  255.  
  256. //
  257. // PlaySoundHandle()
  258. //        Ultility routine to play a sound async.  Maintains a sound channel 
  259. //        and the sound data to do so. 
  260. //
  261. //        Intended for use by external code.
  262. //
  263.  
  264. OSErr    PlaySoundHandle( SndListHandle theSound )
  265. {
  266. OSErr        iErr = noErr;
  267.  
  268.     
  269.     // If a sound is currently playing, stop it and dispose of it's buffer.
  270.     iErr = StopCurrentSound();
  271.     
  272.     // create a new buffer for the selected sound.
  273.     gCurrentSound = theSound;
  274.     iErr = HandToHand((Handle *)&(gCurrentSound));
  275.     
  276.     if (!iErr)
  277.     {
  278.         iErr = PlayCurrentGlobalSound();
  279.         
  280.         if (iErr)
  281.         {
  282.             // FYI, HLock is called in PlayCurrentGlobalSound()
  283.             HUnlock( (Handle)gCurrentSound );
  284.             DisposeHandle( (Handle)gCurrentSound );
  285.             gCurrentSound = nil;
  286.         }    
  287.     }
  288.     
  289.     return(iErr);
  290. }
  291.  
  292. //
  293. // PlayCurrentGlobalSound()
  294. //        Used locally by the object handler to play the current sound.
  295. //
  296.  
  297. static    OSErr    PlayCurrentGlobalSound( void )
  298. {
  299. OSErr    iErr = noErr;
  300.  
  301.     // check for sound channel
  302.     if (!gSoundChannel)
  303.         gSoundChannel = CreateNewSoundChannel();
  304.  
  305.     if (gCurrentSound&&gSoundChannel)
  306.     {
  307.         // Lock the buffer and play the sound.
  308.         gCurSoundHandleStatus = HGetState( (Handle)gCurrentSound );
  309.         HLockHi( (Handle)gCurrentSound );
  310.         // FYI, gCurrentSound is unlocked and disposed of upon return to
  311.         // PlaySoundHandle()
  312.         
  313.         iErr = SndPlay(gSoundChannel,gCurrentSound,true);
  314.     }
  315.     
  316.     return(iErr);
  317. }
  318.  
  319. //
  320. // StopCurrentSound()
  321. //        Stops the current sound and returns memory to original state.
  322. //
  323.  
  324. OSErr    StopCurrentSound( void )
  325. {
  326. SndCommand    cmd;
  327. OSErr        iErr;
  328.  
  329.     if (gCurrentSound&&gSoundChannel)
  330.     {
  331.         cmd.cmd = quietCmd;
  332.         iErr = SndDoImmediate(gSoundChannel,&cmd);
  333.         
  334.         HSetState( (Handle)gCurrentSound, (char)(gCurSoundHandleStatus&0x00FF) );
  335.         
  336.         iErr = MemError();
  337.         if (iErr) return(iErr);
  338.         
  339.         if (!(gCurSoundHandleStatus&kIsWASTESound))
  340.             DisposeHandle( (Handle)gCurrentSound );
  341.             
  342.         gCurrentSound = nil;
  343.         gCurSoundHandleStatus = 0;
  344.         
  345.         return(MemError());
  346.     }
  347.  
  348.     return(noErr);
  349. }
  350. //
  351. // CreateNewSoundChannel()
  352. //        Used to create a new shound channel.
  353. //
  354. static SndChannelPtr    CreateNewSoundChannel( void )
  355. {
  356. OSErr            iErr;
  357. SndChannelPtr    chan;
  358.         
  359.     // allocate a sound channel
  360.     chan = (SndChannelPtr)NewPtrClear(sizeof(SndChannel));
  361.     if ( chan != nil ) 
  362.     {
  363.         chan->qLength = stdQLength;     //128 sound commands
  364.         iErr = SndNewChannel(&chan, sampledSynth, 0, nil);
  365.         if (iErr)
  366.         {
  367.             DisposePtr((Ptr)chan);
  368.             chan = nil;
  369.         }
  370.     }
  371.     return(chan);            // return SndChannelPtr
  372. }
  373.  
  374. //
  375. // CheckSoundStatus()
  376. //        Should be called periodically to dispose of unneeded sound buffers.
  377. //
  378. void CheckSoundStatus( void )
  379. {
  380.     if ((!SoundIsPlaying()) && (gCurrentSound !=nil))
  381.     {
  382.         HSetState( (Handle)gCurrentSound, (char)(gCurSoundHandleStatus&0x00FF) );
  383.                         
  384.         if (!gCurSoundHandleStatus&kIsWASTESound)
  385.             DisposeHandle( (Handle)gCurrentSound );
  386.             
  387.         gCurrentSound = nil;
  388.         gCurSoundHandleStatus = 0;
  389.     }        
  390. }
  391.  
  392. //
  393. // SoundIsPlaying()
  394. //        Returns true if a sound is being played by the object handler, 
  395. //        false if not.
  396. //
  397.  
  398. Boolean    SoundIsPlaying( void )
  399. {
  400. OSErr        iErr;
  401. SCStatus    theStatus;
  402.  
  403.     if (gSoundChannel)
  404.     {
  405.         iErr = SndChannelStatus(gSoundChannel,sizeof(SCStatus),&theStatus);
  406.         if (( theStatus.scChannelBusy )&&(gCurrentSound))
  407.             return( true );
  408.     }
  409.     
  410.     return( false );
  411. }